package org.lestr.secuel.noyau.sauvegarde;

import java.io.File;
import java.io.FileOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import org.jdom.Attribute;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.Namespace;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;

import org.lestr.secuel.m3ds.sauvegarde.M3DSEnregistrementException;
import org.lestr.secuel.m3ds.sauvegarde.M3DSEnregistreur;
import org.lestr.secuel.noyau.Jeu;
import org.lestr.secuel.noyau.Scene;
import org.lestr.secuel.noyau.systemeLogique.Condition;
import org.lestr.secuel.noyau.systemeLogique.Effet;
import org.lestr.secuel.noyau.systemeLogique.Regle;
import org.lestr.secuel.noyau.systemeLogique.SystemeLogique;


public class NoyauEnregistreur {
	
	
	// Définition de constantes
	public static final Namespace espaceDeNommage = Namespace.getNamespace("sn", "secuel::noyau");
	
	
	// Déclaration des attributs
	private M3DSEnregistreur enregisteurM3DS;
	

	/** Constructeur */
	public NoyauEnregistreur(){
	
		// Instanciation des attributs
		enregisteurM3DS = new M3DSEnregistreur();
		
	}// FIN Constructeur


	/** Enregistre un jeu */
	public static void enregistrer(Jeu jeu, File fichier, int compression) throws M3DSEnregistrementException {
		
		// Initialise la sauvegarde
		Document jeuXML = new Document();
		jeuXML.setRootElement(new Element("jeu", espaceDeNommage));
		
		// Compile le jeu
		jeuXML.setRootElement(new NoyauEnregistreur().compilerJeu(jeu));
		
		// Enregistre dans le fichier
		try{
	  
			// Format classique
			XMLOutputter sortie = new XMLOutputter(Format.getPrettyFormat());
  
			// Compresser le flux
			ZipOutputStream flux = new ZipOutputStream(new FileOutputStream(fichier));
			flux.setLevel(compression);
			flux.putNextEntry(new ZipEntry("Secuel"));
			
			// On enregistre
			sortie.output(jeuXML, flux);
			
			// Ferme le flux compressé
			flux.closeEntry();
			flux.close();
      
		}catch (java.io.IOException e){}
		
	}// FIN enregistrerJeu

	
	/** Compile un jeu */
	public Element compilerJeu(Jeu jeu) throws M3DSEnregistrementException {
		
		// Variables locales
		Element rslt = new Element("jeu", espaceDeNommage);
		
		// Mémorise le nom du jeu
		rslt.setAttribute(new Attribute("nom", jeu.getNom(), espaceDeNommage));
		
		// Parcours et mémorise les scènes du jeu
		for(Scene scène : jeu.getScènes()){
			
			// Mémorise la scène courante
			rslt.addContent(compilerScène(scène));
			
		}
		
		// Retourne le résultat
		return rslt;
		
	}// FIN compilerjeu

	
	/** Compile une scène */
	public Element compilerScène(Scene scène) throws M3DSEnregistrementException {
		
		// Variables locales
		Element rslt = new Element("scène", espaceDeNommage);
		
		// Mémorise le nom de la scène
		rslt.setAttribute(new Attribute("nom", scène.getNom(), espaceDeNommage));

		// Mémorise l'univers de la scène
		rslt.addContent(enregisteurM3DS.compilerUnivers(scène.getUnivers()));

		// Mémorise le système logique de la scène
		rslt.addContent(compilerSystèmeLogique(scène.getSystèmeLogique()));
		
		// Retourne le résultat
		return rslt;
		
	}// FIN compilerScène


	/** Compile un système logique */
	public Element compilerSystèmeLogique(SystemeLogique systèmeLogique) throws M3DSEnregistrementException {
		
		// Variables locales
		Element rslt = new Element("systèmeLogique", espaceDeNommage);
		
		// Parcours les règles du système logique
		for(Regle règle : systèmeLogique.getRègles()){
			
			// Mémorise la règle courante
			rslt.addContent(compilerRègle(règle));
			
		}
		
		// Retourne le résultat
		return rslt;
		
	}// FIN compilerSystèmeLogique

	
	/** Compile une règle */
	public Element compilerRègle(Regle règle) throws M3DSEnregistrementException {
		
		// Variables locales
		Element rslt = new Element("règle", espaceDeNommage);
		
		// Mémorise le nom de la règle
		rslt.setAttribute(new Attribute("nom", règle.getNom(), espaceDeNommage));
		
		// Parcours les conditions de la règle
		for(Condition condition : règle.getConditions()){
			
			// Mémorise la condition courante
			rslt.addContent(compilerCondition(condition));
			
		}
		
		// Parcours les effets de la règle
		for(Effet effet : règle.getEffets()){
			
			// Mémorise l'effet courant
			rslt.addContent(compilerEffet(effet));
			
		}
		
		// Retourne le résultat
		return rslt;
		
	}// FIN compilerRègle

	
	/** Compile une condition */
	public Element compilerCondition(Condition condition) throws M3DSEnregistrementException {
		
		// Variables locales
		Element rslt = new Element("condition", espaceDeNommage);
		
		// Mémorise le nom de la condition et le nom de son type
		rslt.setAttribute(new Attribute("nom", condition.getNom(), espaceDeNommage));
		rslt.setAttribute(new Attribute("classe", condition.getClass().getName(), espaceDeNommage));
		
		// Mémorise le code de sauvegarde de la condition
		rslt.addContent(condition.compiler());
		
		// Retourne le résultat
		return rslt;
		
	}// FIN compilerCondition

	
	/** Compile un effet */
	public Element compilerEffet(Effet effet) throws M3DSEnregistrementException {
		
		// Variables locales
		Element rslt = new Element("effet", espaceDeNommage);
		
		// Mémorise le nom de l'effet et le nom de son type
		rslt.setAttribute(new Attribute("nom", effet.getNom(), espaceDeNommage));
		rslt.setAttribute(new Attribute("classe", effet.getClass().getName(), espaceDeNommage));
		
		// Mémorise le code de sauvegarde de l'effet
		rslt.addContent(effet.compiler());
		
		// Retourne le résultat
		return rslt;
		
	}// FIN compilerEffet
	
	
}// FIN Classe
